﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using TPA.DataAccess;
using System.Linq.Expressions;
using System.Threading;

namespace TVProgramAnalyst.TimeLine
{
    public partial class frmAutoWizard : Form
    {
        enum Step
        {
            ImportLogFiles, ConfirmTimeline, Complete//ConfirmChannel, ConfirmProgram, 
        }
        const int _MaxStep = 4;

        #region Define variables
        /// <summary>
        /// Wizard Steps
        /// </summary>
        Step _CurrentStep = Step.ImportLogFiles;
        bool _IsProgramLogReady = false; 
        bool _IsAdvLogReady = false;
        /// <summary>
        /// Ready flag for Step 1 ImportLogFile
        /// </summary>
        bool _IsImportLogFilesReady = false; 
        bool _IsConfirmTimelineReady = false;
        /// <summary>
        /// Ready flag for enable finish button
        /// </summary>
        //bool _AllReady = false;
        /// <summary>
        /// Flag for log file re-import
        /// </summary>
        bool _IsLogSourceChanged = false;
        /// <summary>
        /// Program logs from external excel file
        /// </summary>
        List<KeyPoint> _ProgramLog;
        /// <summary>
        /// Advertisement logs from external excel file
        /// </summary>
        List<KeyPoint> _AdvertisementLog;
        public List<List<KeyPoint>> _ProgramLogList;
        public List<List<KeyPoint>> _AdvertisementLogList;
        #endregion

        public frmAutoWizard()
        {
            InitializeComponent();
        }

        private void frmAutoWizard_Load(object sender, EventArgs e)
        {
            this.Height = 500;
            this.Width = 540;
            pnlStep2.Location = pnlStep1.Location;
            pnlStep3.Location = pnlStep1.Location;
            _AdvertisementLog = new List<KeyPoint>();
            _ProgramLog = new List<KeyPoint>();
            _ProgramLogList = new List<List<KeyPoint>>();
            _AdvertisementLogList = new List<List<KeyPoint>>();
            TPAProgram._TimeLine = new List<KeyPoint>();
            //BLLFactory.TimeLineBLL.Refresh();
        }

        #region Step1: ImportLogFiles
        private void btnSelectProgramLogFile_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.InitialDirectory = global.Default.LastOpenLocation;//Environment.GetFolderPath(Environment.SpecialFolder.Personal);
            openFileDialog.Filter = "Excel files (*.xls;*.xlsx; *.xlsm)|*.xls;*.xlsx; *.xlsm|Excel 1997-2003 files (*.xls)|*.xls|Excel 2007-2010 files (*.xlsx)|*.xlsx";
            if(cbAllinone.Checked)
                openFileDialog.Multiselect = true;
            else
                openFileDialog.Multiselect = false;

            if (openFileDialog.ShowDialog(this) == DialogResult.OK)
            {
                global.Default.LastOpenLocation = System.IO.Path.GetDirectoryName(openFileDialog.FileName);
                _ProgramLog = new List<KeyPoint>();
                _ProgramLogList = new List<List<KeyPoint>>();
                if (cbAllinone.Checked)
                {
                    _AdvertisementLog = new List<KeyPoint>();
                    _AdvertisementLogList = new List<List<KeyPoint>>();
                }
                for (int i = 0; i < openFileDialog.FileNames.Length;i++ )
                {
                    string filename = openFileDialog.FileNames[i];
                    string safename = openFileDialog.SafeFileNames[i];
                    lblFileName.Text = safename;
                    pnlProImportResult.Visible = true;
                    ProgramLogReader pr = new ProgramLogReader();
                    try
                    {
                        _ProgramLog=pr.GetProgramLogKeyPoint(filename, "节目", cbAllinone.Checked);
                        _ProgramLogList.Add(_ProgramLog);
                        dgvProgramLog.DataSource = _ProgramLog;
                        _IsProgramLogReady = true;
                        lblRecordNumber.Text = _ProgramLog.Count.ToString();
                        _IsLogSourceChanged = true;
                        if (cbAllinone.Checked)
                        {
                            lblAdvFilename.Text = safename;
                            pnlAdvImportResult.Visible = true;
                            ProgramLogReader pra = new ProgramLogReader();
                            try
                            {
                                _AdvertisementLog= pra.GetAdvertisementLogKeyPoint(filename, "广告");
                                _AdvertisementLogList.Add(_AdvertisementLog);
                                dgvAdvertisementLog.DataSource = _AdvertisementLog;
                                _IsAdvLogReady = true;
                                lblAdvRecordNumber.Text = _AdvertisementLog.Count.ToString();
                                _IsLogSourceChanged = true;
                                //if (checkBox1.Checked)
                                //{
                                //    TPAProgram._TimeLine = new List<KeyPoint>();
                                //    RunStep1(_ProgramLog, _AdvertisementLog);
                                //    RunStep2();
                                //}
                            }
                            catch (TPA.DataAccess.TPAException ex)
                            {
                                MessageBox.Show(ex.Source);
                                _IsAdvLogReady = false;
                                lblAdvRecordNumber.Text = "0";
                                _AdvertisementLog = null;
                                dgvAdvertisementLog.DataSource = null;
                            }
                            _IsImportLogFilesReady = _IsAdvLogReady && _IsProgramLogReady;
                            btnNext.Enabled = _IsImportLogFilesReady;
                        }
                    }
                    catch (TPA.DataAccess.TPAException ex)
                    {
                        MessageBox.Show(ex.Source);
                        _IsProgramLogReady = false;
                        lblRecordNumber.Text = "0";
                        _ProgramLog = null;
                        dgvProgramLog.DataSource = null;
                    }

                    

                }
                _IsImportLogFilesReady = _IsAdvLogReady && _IsProgramLogReady;
                btnNext.Enabled = _IsImportLogFilesReady;
                _IsConfirmTimelineReady = !_IsLogSourceChanged;
            }
        }

        private void btnSelectAdvLogFile_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.InitialDirectory = global.Default.LastOpenLocation;// Environment.GetFolderPath(Environment.SpecialFolder.Personal);
            openFileDialog.Filter = "Excel files (*.xls;*.xlsx; *.xlsm)|*.xls;*.xlsx; *.xlsm|Excel 97-2003 files (*.xls)|*.xls|Excel 2007-2010 files (*.xlsx)|*.xlsx";
            openFileDialog.Multiselect = false;
            if (openFileDialog.ShowDialog(this) == DialogResult.OK)
            {
                _AdvertisementLog = new List<KeyPoint>();
                _AdvertisementLogList = new List<List<KeyPoint>>();
                global.Default.LastOpenLocation = System.IO.Path.GetDirectoryName(openFileDialog.FileName);
                lblAdvFilename.Text = openFileDialog.SafeFileName;
                pnlAdvImportResult.Visible = true;
                ProgramLogReader pr = new ProgramLogReader();
                try
                {
                    _AdvertisementLog = pr.GetAdvertisementLogKeyPoint(openFileDialog.FileName, "广告");
                    _AdvertisementLogList.Add(_AdvertisementLog);
                    dgvAdvertisementLog.DataSource = _AdvertisementLog;
                    _IsAdvLogReady = true;
                    lblAdvRecordNumber.Text = _AdvertisementLog.Count.ToString();
                    _IsLogSourceChanged = true;
                }
                catch (TPA.DataAccess.TPAException ex)
                {
                    MessageBox.Show(ex.Source);
                    _IsAdvLogReady = false;
                    lblAdvRecordNumber.Text = "0";
                    _AdvertisementLog = null;
                    dgvAdvertisementLog.DataSource = null;
                }
                _IsImportLogFilesReady = _IsAdvLogReady && _IsProgramLogReady;
                btnNext.Enabled = _IsImportLogFilesReady;
            }
        }

        private void RunStep1()
        {
            GotoStep(Step.ConfirmTimeline);
            pnlStep2.Visible = true;
            btnPrevious.Enabled = true;
            if (_IsLogSourceChanged && _IsImportLogFilesReady)
            {
                //pnlAnalyzing.Visible = true;
                //combine timeline
                //lblProgressTitle.Text = "正在合并时间线......";
                //CombineTimeline();
                
                for (int i = 0; i < _ProgramLogList.Count; i++)
                {
                    frmProgressBar frmpb = new frmProgressBar() { WorkingText = "正在合并时间线......", ProgramLog=_ProgramLogList[i], AdvertisementLog=_AdvertisementLogList[i] };
                    frmpb.ShowDialog(this);
                }
                int tlcount = TPAProgram._TimeLine.Count;
                dgvTimeline.DataSource = TPAProgram._TimeLine;
                lblTimelineRecordNumber.Text = tlcount.ToString();
                //TPAProgram._TimeLine.Last().DateTimeOut - TPAProgram._TimeLine.First().DateTimeIn;
                lblTotalTime.Text = GetTimeLineTotalHours();// + " Hour(s)";
                //parse program
                //lblProgressTitle.Text = "正在分析节目和频道......";
                ParsePrograms(TPAProgram._TimeLine, out TPAProgram._ExistingPrograms, out TPAProgram._NewPrograms, out TPAProgram._ConflictPrograms, out TPAProgram._NewChannels, out TPAProgram._ExistingChannels);
                //pnlAnalyzing.Visible = false;
                _IsLogSourceChanged = false;
            }
            btnFinish.Enabled = _IsConfirmTimelineReady;

        }

        private void RunStep1(bool skippreview)
        {
            GotoStep(Step.ConfirmTimeline);
            pnlStep2.Visible = true;
            btnPrevious.Enabled = true;
            if (_IsLogSourceChanged && _IsImportLogFilesReady)
            {
                //pnlAnalyzing.Visible = true;
                //combine timeline
                //lblProgressTitle.Text = "正在合并时间线......";
                //CombineTimeline();

                for (int i = 0; i < _ProgramLogList.Count; i++)
                {
                    GotoStep(Step.ConfirmTimeline);
                    _IsConfirmTimelineReady = false;
                    pnlStep2.Visible = true;
                    TPAProgram._TimeLine = new List<KeyPoint>();
                    frmProgressBar frmpb = new frmProgressBar() { WorkingText = "正在合并时间线......", ProgramLog = _ProgramLogList[i], AdvertisementLog = _AdvertisementLogList[i] };
                    frmpb.ShowDialog(this);
                    ParsePrograms(TPAProgram._TimeLine, out TPAProgram._ExistingPrograms, out TPAProgram._NewPrograms, out TPAProgram._ConflictPrograms, out TPAProgram._NewChannels, out TPAProgram._ExistingChannels);
                    RunStep2();
                }
                //dgvTimeline.DataSource = TPAProgram._TimeLine;
                //lblTimelineRecordNumber.Text = TPAProgram._TimeLine.Count.ToString();
                //double totaltime = TPAProgram._TimeLine.Sum(tls => (tls.DateTimeOut - tls.DateTimeIn).Seconds);//TPAProgram._TimeLine.Last().DateTimeOut - TPAProgram._TimeLine.First().DateTimeIn;
                //lblTotalTime.Text = TimeSpan.FromSeconds(totaltime).Hours + " Hour(s)";
                //parse program
                //lblProgressTitle.Text = "正在分析节目和频道......";
                //pnlAnalyzing.Visible = false;
                _IsLogSourceChanged = false;
            }
            btnFinish.Enabled = _IsConfirmTimelineReady;
        }
        #endregion

        #region Step 2: ConfirmChannel
        private void RunStep2()
        {
            if (!_IsConfirmTimelineReady)
            {
                //pnlAnalyzing.Visible = true;

                //save channels
                //lblProgressTitle.Text = "正在保存新频道......";
                SaveChannels();
                //save programs
                //lblProgressTitle.Text = "正在保存新节目......";
                SavePrograms();
                //parse program again
                //lblProgressTitle.Text = "重新分析节目和频道......";
                ParsePrograms(TPAProgram._TimeLine, out TPAProgram._ExistingPrograms, out TPAProgram._NewPrograms, out TPAProgram._ConflictPrograms, out TPAProgram._NewChannels, out TPAProgram._ExistingChannels);
                //save timeline to database
                //pnlAnalyzing.Visible = false;
                //lblProgressTitle.Text = "正在保存时间线......";
                try
                {
                    //SaveTimeline(TPAProgram._TimeLine);
                    frmProgressBar frmpb = new frmProgressBar() { WorkingText = "正在保存时间线......" };
                    frmpb.ShowDialog(this);
                    lblSavedTimelinerecord.Text = TPAProgram._TimeLine.Count.ToString();
                    lblTotalTime.Text = GetTimeLineTotalHours();// + " Hour(s)";
                    lblTotalProgram.Text = (TPAProgram._ConflictPrograms.Count + TPAProgram._ExistingPrograms.Count + TPAProgram._NewPrograms.Count).ToString();
                    _IsConfirmTimelineReady = true;
                    GotoStep(Step.Complete);
                    btnNext.Enabled = false;
                    btnFinish.Enabled = _IsConfirmTimelineReady;
                    pnlStep3.Visible = true;
                    //cannot push previous button and cancel button after write to database
                    btnPrevious.Enabled = false;
                    btnCancel.Enabled = false;
                }
                catch (TPAException ex)
                {
                    MessageBox.Show("错误: " + ex.Source);
                    _IsConfirmTimelineReady = false;
                }
                finally
                {
                    
                }
            }
            else
            {
                GotoStep(Step.Complete);
                btnNext.Enabled = false;
                btnFinish.Enabled = _IsConfirmTimelineReady;
                pnlStep3.Visible = true;
                //cannot push previous button and cancel button after write to database
                btnPrevious.Enabled = false;
                btnCancel.Enabled = false;
            }
        }
        #endregion

        #region Wizard navigation
        private void GotoStep(Step step)
        {
            _CurrentStep = step;
            //show next step panel and hide all other panels
            HideAllStepPanel();
        }
        private void HideAllStepPanel()
        {
            pnlStep1.Visible = false;
            pnlStep2.Visible = false;
            pnlStep3.Visible = false;
        }

        private void btnPrevious_Click(object sender, EventArgs e)
        {
            switch (_CurrentStep)
            {
                case Step.ConfirmTimeline:
                   btnFinish.Enabled = _IsConfirmTimelineReady;
                    GotoStep(Step.ImportLogFiles);
                    pnlStep1.Visible = true;
                    btnPrevious.Enabled = false;
                    break;
                case Step.Complete:
                    GotoStep(Step.ConfirmTimeline);
                    btnNext.Enabled = true;
                    btnFinish.Enabled = _IsConfirmTimelineReady;
                    pnlStep2.Visible = true;
                    break;
            }
        }
        private void btnNext_Click(object sender, EventArgs e)
        {
            switch (_CurrentStep)
            {
                case Step.ImportLogFiles:
                    if (checkBox1.Checked)
                    {
                        RunStep1(checkBox1.Checked);
                    }
                    else{
                        RunStep1();
                    }
                    break;
                case Step.ConfirmTimeline:
                    RunStep2();
                    break;
            }
        }

        #endregion

        #region Combine Timeline
        ///// <summary>
        ///// Combine _ProgramLog and _AdvertisementLog to _Timeline
        ///// </summary>
        //private void CombineTimeline()
        //{
        //    TPAProgram._TimeLine = new List<KeyPoint>();
        //    probarAnalyzing.Minimum = 0;
        //    probarAnalyzing.Maximum = _ProgramLog.Count + _AdvertisementLog.Count;
        //    probarAnalyzing.Value = 0;

        //    for (int pindex = 0, aindex = 0; pindex < _ProgramLog.Count || aindex < _AdvertisementLog.Count; )
        //    {
        //        KeyPoint currentP = null, currentA = null;
        //        if (pindex < _ProgramLog.Count)
        //        {
        //            currentP = _ProgramLog[pindex];
        //        }
        //        if (aindex < _AdvertisementLog.Count)
        //        {
        //            currentA = _AdvertisementLog[aindex];
        //        }
        //        if (currentA != null && currentP != null)
        //        {
        //            if (currentP.DateTimeIn < currentA.DateTimeIn)
        //            {
        //                //Add current program to timeline;
        //                Helper.TimelineHelper.JoinKeyPoint(TPAProgram._TimeLine, currentP);
        //                pindex++;
        //                probarAnalyzing.PerformStep();
        //            }
        //            else
        //            {
        //                //add current advertisement to timeline;
        //                Helper.TimelineHelper.JoinKeyPoint(TPAProgram._TimeLine, currentA);
        //                aindex++;
        //                probarAnalyzing.PerformStep();
        //            }
        //        }
        //        else if (currentA != null)
        //        {
        //            Helper.TimelineHelper.JoinKeyPoint(TPAProgram._TimeLine, currentA);
        //            aindex++;
        //            probarAnalyzing.PerformStep();
        //        }
        //        else if (currentP != null)
        //        {
        //            Helper.TimelineHelper.JoinKeyPoint(TPAProgram._TimeLine, currentP);
        //            pindex++;
        //            probarAnalyzing.PerformStep();
        //        }
        //        //lblTotalTime.Text = totaltime.
        //    }
        //    //dataGridView3.DataSource = TPAProgram._TimeLine;
        //    dgvTimeline.DataSource = TPAProgram._TimeLine;
        //    lblTimelineRecordNumber.Text = TPAProgram._TimeLine.Count.ToString();
        //    TimeSpan totaltime = TPAProgram._TimeLine.Last().DateTimeOut - TPAProgram._TimeLine.First().DateTimeIn;
        //    lblTotalTime.Text = totaltime.TotalHours + " Hour(s)";
        //}
        #endregion

        #region Parse and save programs
        private void ParsePrograms(List<KeyPoint> timeline, out List<TPA.DataAccess.Program> existingprograms,
     out List<TPA.DataAccess.Program> newprograms, out List<TPA.DataAccess.Program> multiexistingprograms,
            out List<Channel> newchannels, out List<Channel> existingchannels)
        {
            existingprograms = new List<TPA.DataAccess.Program>();
            newprograms = new List<TPA.DataAccess.Program>();
            multiexistingprograms = new List<TPA.DataAccess.Program>();
            newchannels = new List<Channel>();
            existingchannels = new List<Channel>();

            IList<KeyPoint> distinctprogramlist =
                (from kp in timeline
                group kp by new { kp.Label } into kpg
               select kpg.FirstOrDefault()).ToList() ;

           

            IList<TPA.DataAccess.Program> AllProgramInDatabase = BLLFactory.ProgramBLL.GetPrograms().ToList();

            foreach (KeyPoint kp in distinctprogramlist)
            {
                //lblConflictedNumbers.Text = multiexistingprograms.Count.ToString();
                //lblExistingNumber.Text = existingprograms.Count.ToString();
                //lblNewNumber.Text = newprograms.Count.ToString();
                IEnumerable<TPA.DataAccess.Program> programs_in_database = from p in AllProgramInDatabase where p.Name==kp.Label select p;//BLLFactory.ProgramBLL.GetPrograms(kp.Label);
                int count = programs_in_database.Count();
                if (count == 0)
                {
                    //if (newprograms.Count(p => p.Name == kp.Label) == 0)
                    //{
                        newprograms.Add(Helper.TimelineHelper.CreateProgramfromKeyPoint(kp));
                        //BLLFactory.ProgramBLL.Add(target);
                    //}
                }
                else if (count == 1)
                {
                    //if (existingprograms.Count(p => p.Name == kp.Label) == 0)
                    //{
                        existingprograms.Add(programs_in_database.Single());
                    //}
                }
                else
                {
                    //if (multiexistingprograms.Count(p => p.Name == kp.Label) == 0)
                    //{
                        multiexistingprograms.Add(Helper.TimelineHelper.CreateProgramfromKeyPoint(kp));
                    //}
                    //BLLFactory.ProgramBLL.Add(target);
                }
                
            }

            

            //Analyzing channels
            #region analyzing channels
            IList<string> channellist =
               (from kp in timeline
                group kp by new { kp.Channel } into kpc
                select kpc.FirstOrDefault().Channel).ToList();
            foreach (string channelname in channellist)
            {
                Channel c = BLLFactory.ChannelBLL.Get(channelname);
                if (c != null)
                {
                    if (existingchannels.Count(ch => ch.Name == channelname) == 0)
                        existingchannels.Add(c);
                }
                else
                {
                    if (newchannels.Count(ch => ch.Name == channelname) == 0)
                        newchannels.Add(new Channel() { Name = channelname });
                }
            }
            #endregion
            //BLLFactory.ProgramBLL.SaveChanges();
            //lblAnalysing.Visible = false;
            lblProgramNumber.Text = (newprograms.Count + multiexistingprograms.Count + existingprograms.Count).ToString();
            lblChannelNumber.Text = (newchannels.Count + existingchannels.Count).ToString();
            lblTotalChannels.Text = lblChannelNumber.Text;
            lblTotalProgram.Text = lblProgramNumber.Text;
            
        }

        string _lasterror;
        private void SavePrograms()
        {
            _lasterror = "";
            int saved = 0, cancelled = 0;
            //lblSaving.Visible = true;
            foreach (Program p in TPAProgram._NewPrograms)
            {
                try
                {
                    BLLFactory.ProgramBLL.Add(p);
                    saved++;
                    //lblNewSaved.Text = saved.ToString();
                }
                catch (Exception ex)
                {
                    cancelled++;
                    _lasterror = ex.Message;
                }
            }
            BLLFactory.ProgramBLL.SaveChanges();
            _lasterror = saved + " saved; " + cancelled + " cancelled\n\r" + _lasterror;
            //lblSaving.Visible = false;
            lblNewPrograms.Text = saved.ToString();
            
        }

        private void SaveChannels()
        {
            _lasterror = "";
            int saved = 0, cancelled = 0;
            foreach (Channel c in TPAProgram._NewChannels)
            {
                try
                {
                    BLLFactory.ChannelBLL.Add(c);
                    saved++;
                    //lblNewChannelsSaved.Text = saved.ToString();
                }
                catch (Exception ex)
                {
                    cancelled++;
                    _lasterror = ex.Message;
                }
            }
            BLLFactory.ChannelBLL.SaveChanges();
            _lasterror = saved + " saved; " + cancelled + " cancelled\n\r" + _lasterror;
            lblNewChannels.Text = saved.ToString();
        }

        #endregion

       

        #region Invoke other forms
        private void lblProgramNumber_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            frmProgramResult frm = new frmProgramResult();
            frm.ShowDialog(this);
        }
        #endregion

        private void btnFinish_Click(object sender, EventArgs e)
        {
            TPAProgram._TimeLine.Clear();
            this.Dispose(true);
        }

        private void cbAllinone_CheckedChanged(object sender, EventArgs e)
        {
            //checkBox1.Enabled = cbAllinone.Checked;
        }

        private string GetTimeLineTotalHours()
        {
            double totaltime = TPAProgram._TimeLine.Sum(tls => (tls.DateTimeOut - tls.DateTimeIn).Seconds);//TPAProgram._TimeLine.Last().DateTimeOut - TPAProgram._TimeLine.First().DateTimeIn;
            return TimeSpan.FromSeconds(totaltime).ToString();
        }
    }
}
